using System;
using System.Collections.Generic;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
namespace Nyanimals
{
	public sealed class CContextManager
	{
		private static readonly CContextManager instance = new CContextManager();
		
		// contexts
        private List<CBaseContext> ContextList;
        private List<CBaseContext> RemoveContexts;
		
		// shader uniforms
		private Dictionary<string, int> StaticUniformMap;
		private Dictionary<string, int> AnimatedUniformMap;
		
		private int staticShaderIndex;
		private int animatedShaderIndex;
		
		public int StaticShaderIndex
		{
			get { return staticShaderIndex;}
		}
		
		public int GetStaticUniform(string szUniform)
		{
			return StaticUniformMap[szUniform];
		}
		public int GetAnimatedUniform(string szUniform)
		{
			return AnimatedUniformMap[szUniform];
		}
		
		private CContextManager ()
		{
            ContextList = new List<CBaseContext>();
            RemoveContexts = new List<CBaseContext>();
			
			StaticUniformMap = new Dictionary<string, int>();
			AnimatedUniformMap = new Dictionary<string, int>();
			
			// get everything with the static shader
			tShader staticShader;
			staticShaderIndex = CShaderManager.Instance.AddShader("Static");
			CShaderManager.Instance.GetShader(staticShaderIndex, out staticShader);
			StaticUniformMap["WorldViewProj"] = staticShader.Shader.FindUniform("WorldViewProj"); // VS - float4x4
			StaticUniformMap["Diffuse"] = staticShader.Shader.FindUniform("Diffuse"); // FS - sampler2D
			
			// bind the static attributes
			staticShader.Shader.SetAttributeBinding(0, "position");
			staticShader.Shader.SetAttributeBinding(1, "uv");
			
			// get everythign with the animated shader
			tShader animatedShader;
			animatedShaderIndex = CShaderManager.Instance.AddShader("Animated");
			CShaderManager.Instance.GetShader(animatedShaderIndex, out animatedShader);
			AnimatedUniformMap["WorldViewProj"] = animatedShader.Shader.FindUniform("WorldViewProj"); // VS - float4x4
			AnimatedUniformMap["gBones"] = animatedShader.Shader.FindUniform("gBones_00"); // VS - float4[120] (30 vector4x4)
			AnimatedUniformMap["Diffuse"] = animatedShader.Shader.FindUniform("Diffuse"); // FS - sampler2D
			
			// bind the animated attributes
			animatedShader.Shader.SetAttributeBinding(0, "position");
			animatedShader.Shader.SetAttributeBinding(1, "uv");
			animatedShader.Shader.SetAttributeBinding(2, "BoneIndex");
			animatedShader.Shader.SetAttributeBinding(3, "BoneWeights");
		}
		
		public static CContextManager Instance
		{
			get { return instance;}
		}
        
        public int AddStaticContext(CStaticContext context)
        {
            int returnIndex = ContextList.Count;
            ContextList.Add(context);
            
            return returnIndex;
        }       
        public int AddStaticContext(int MeshIndex, Matrix4 matrix)
        {
            int returnIndex = ContextList.Count;
            CStaticContext context = new CStaticContext();
            
            context.Active = true;
            context.MeshIndex = MeshIndex;
            context.ShaderIndex = staticShaderIndex;
            context.WorldMatrix = matrix;
            
            ContextList.Add(context);
            
            return returnIndex;
        }       
		
		public int AddAnimatedContext(int MeshIndex, Matrix4 matrix)
		{
			int returnIndex = ContextList.Count;
			CAnimatedContext context = new CAnimatedContext();
			
			context.Active = true;
			context.MeshIndex = MeshIndex;
			
			// point to skeletal shader
			context.ShaderIndex = animatedShaderIndex;
			context.WorldMatrix = matrix;
			
			ContextList.Add(context);
			
			return returnIndex;
		}
        
        public void RemoveContext(CBaseContext context)
        {
            RemoveContexts.Add(context);
        }
        public void FlushContext()
        {
            if(RemoveContexts.Count > 0)
            {
                Console.WriteLine("flushing " + RemoveContexts.Count + " contexts");
            }
            foreach(CBaseContext context in RemoveContexts)
            {
                if(context != null)
                    ContextList.Remove(context);
            }
            RemoveContexts.Clear();
        }
		
        public void GetContext(int contextIndex, out CBaseContext context)
        {
            context = ContextList[contextIndex];
        }
        
        public CBaseContext GetContext(int contextIndex)
        {
            return ContextList[contextIndex];
        }
		
        public void Render(GraphicsContext graphics)
        {
            foreach(CBaseContext context in ContextList)
            {
                if(context != null)
                    context.Render(graphics);
            }
        }
	}
}

